package controllers

import (
	"encoding/json"
	"github.com/pkg/errors"
	"nft-server/common"
	"nft-server/db"
	"nft-server/errcode"
	"nft-server/logger"
	"nft-server/payment"
	"nft-server/service"
	"nft-server/util"
	"time"
)

const (
	PaymentNotifyURI = "/v1/payment/notify"
	PrePaymentURI    = "/v1/payment/prepay"
	PaymentWebsocket = "/v1/payment/ws"
)

var (
	message = make(map[string]payment.PaymentMessage)
)

type PaymentController struct {
	payment.PaymentCommonController
}

//PaymentNotifyWithWebSocket 和前端建立链接
func (pc *PaymentController) PaymentNotifyWithWebSocket() {
	req := common.OrderReq{}
	if err := json.Unmarshal(pc.Ctx.Input.RequestBody, &req); err != nil {
		logger.Error("PaymentNotifyWithWebSocket Unmarshal error: %v", err)
		pc.HandleErrCode(errcode.E.Base.RequestInvalid.WithErr(err))
		return
	}

	//从缓存中获取订单
	order, err := service.GetOrderFromRedis(req.UserId, db.RedisPool)
	if err != nil {
		//缓存获取失败从db中获取
		order, err = service.GetOrderWithId(req.OrderId)
		if err != nil {
			logger.Error(err.Error())
			pc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("订单号不存在"))
			return
		}
	}
	//判断订单是否过期或未处于可支付状态
	if order.OrderStatus != util.TradeNoPay || order.ExpireTime.Before(time.Now()) == true {
		_, _ = service.DealWithOrder(order.OrderId, util.TradeClosed, nil)
		pc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("订单已过期或已支付"))
		return
	}
	//未接入第三方时测试
	if payment.UseThirdParty == false {
		//模拟付款时间
		nowTime := time.Now()
		//作为producer往队列中写入信息，为了websocket通知消息
		msg := payment.PaymentMessage{
			OrderId:     req.OrderId,
			OrderStatus: util.TradeSuccess,
		}
		message[req.OrderId] = msg
		//根据支付状态修改系统订单状态
		_, err := service.DealWithOrder(req.OrderId, util.TradeSuccess, &nowTime)
		if err != nil {
			logger.Error("ApplyAssets failed: %v", err)
			_, _ = service.DealWithOrder(req.OrderId, util.TradeClosed, nil)
			pc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("出现错误，领取失败"))
			return
		}

	}
	webMsg := message[req.OrderId]
	pc.HandleBusinessObj(webMsg)
	//主动查询数据库
}
func (pc *PaymentController) CheckParameterForPrePay(req common.OrderReq) error {
	if len(req.OrderId) < 1 {
		err := errors.Errorf("订单号长度不合法")
		pc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage(err.Error()))
		return err
	}
	if len(req.PaymentMethod) == 0 {
		err := errors.Errorf("请选择支付方式")
		pc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage(err.Error()))
		return err
	}
	return nil
}

// PrePay 创建预支付二维码链接
func (pc *PaymentController) PrePay() {
	req := common.OrderReq{}
	if err := json.Unmarshal(pc.Ctx.Input.RequestBody, &req); err != nil {
		logger.Error("PrePay Unmarshal error: %v", err)
		pc.HandleErrCode(errcode.E.Base.RequestInvalid.WithErr(err))
		return
	}
	err := pc.CheckParameterForPrePay(req)
	if err != nil {
		return
	}
	//尝试从缓存中获取订单
	order, err := service.GetOrderFromRedis(req.UserId, db.RedisPool)
	if err != nil {
		//缓存获取失败从db中获取
		order, err = service.GetOrderWithId(req.OrderId)
		if err != nil {
			logger.Error(err.Error())
			pc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("订单号不存在"))
			return
		}
	}
	//判断订单是否过期或未处于可支付状态
	if order.OrderStatus != util.TradeNoPay || order.ExpireTime.Before(time.Now()) == true {
		_, _ = service.DealWithOrder(order.OrderId, util.TradeClosed, nil)
		pc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("订单已过期或已支付"))
		return
	}
	prepayInfo := payment.PrepayInfo{
		Description:   "自定义数据说明",
		OutTradeNo:    order.OrderId,
		TimeExpire:    order.ExpireTime,
		NotifyUrl:     PaymentNotifyURI,
		Price:         order.Price,
		Currency:      order.Currency,
		PaymentMethod: req.PaymentMethod,
	}
	//创建订单之后调用预支付,通过NotifyOrderURI接受支付结果通知
	codeUrl, err := payment.ExamplePrepay(prepayInfo)
	payInfo, _, err := payment.ExampleQueryOrderByOutTradeNo(order.OrderId, req.PaymentMethod)
	if err != nil {
		logger.Error(err.Error())
		pc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("第三方支付平台出错"))
		return
	}
	//更新系统订单的第三方平台订单号
	err = service.UpdateOrderThirdPartyId(order.OrderId, *payInfo.TransactionId)
	if err != nil {
		logger.Error(err.Error())
		pc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("获取第三方平台订单出错"))
		return
	}
	response := common.PaymentInfo{CodeUrl: codeUrl}
	pc.HandleBusinessObj(response)
}

// PaymentNotify 第三方支付通知url--post方法--给第三方平台进行调用
func (pc *PaymentController) PaymentNotify() {
	req := payment.OrderNotifyReq{}
	if err := json.Unmarshal(pc.Ctx.Input.RequestBody, &req); err != nil {
		logger.Error("PaymentNotify Unmarshal error: %v", err)
		pc.HandlePaymentNotifyError(errcode.E.Base.RequestInvalid.WithErr(err))
		return
	}
	transaction, _, err := payment.DecryptFromBody(&req)
	if err != nil {
		pc.HandlePaymentNotifyError(errcode.E.Base.RequestInvalid.WithErr(err))
		return
	}

	//通知系统第三方订单状态已经修改
	msg := payment.PaymentMessage{
		OrderId:     *transaction.OutTradeNo,
		OrderStatus: *transaction.TradeState,
	}
	message[msg.OrderId] = msg
	//系统根据第三方支付状态修改系统订单状态
	nowTime := time.Now()
	//修改系统订单
	_, err = service.DealWithOrder(*transaction.OutTradeNo, *transaction.TradeState, &nowTime)

	if err != nil {
		logger.Error("DealWithOrder error: %v", err)
		pc.HandlePaymentNotifyError(errcode.E.Base.RequestInvalid.WithErr(err))
		return
	}
	pc.HandlePaymentNotifySuccess()
}
